
package com.wmh.baseservice.system.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wmh.baseservice.common.ex.ServiceException;
import com.wmh.baseservice.common.mybatisplus.methods.CommonServiceImpl;
import com.wmh.baseservice.common.redis.utils.RedisUtil;
import com.wmh.baseservice.common.utils.CommUtil;
import com.wmh.baseservice.common.utils.HttpRequestUtil;
import com.wmh.baseservice.common.utils.LogUtil;
import com.wmh.baseservice.system.mapper.SysLocationMapper;
import com.wmh.baseservice.system.pojo.SysLocation;
import com.wmh.baseservice.system.pojo.vo.SysLocationTreeVO;
import com.wmh.baseservice.system.service.SysLocationService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

/**
 * @author wmh generator
 * @since 2022-01-17
 */
@Service
public class SysLocationServiceImpl extends CommonServiceImpl<SysLocationMapper, SysLocation> implements SysLocationService {

    @Resource
    SysLocationMapper sysLocationMapper;

    @Resource
    RedisUtil redisUtil;

    @Override
    public SysLocation getLocationInfo(String lng, String lat) {
        //根据经纬度获取当前区域
        SysLocation sysLocation;
        try {
            String address = HttpRequestUtil.sendGet("https://apis.map.qq.com/ws/geocoder/v1/?", String.format("location=%s,%s&key=%s", lat, lng, "BIEBZ-KBNRD-FII4L-PUKSS-I5YZE-AUF3J"));
            if (!CommUtil.checkNull(address)) {
                throw new ServiceException("获取地区信息错误");
            }
            JSONObject object = JSONObject.parseObject(address);
            LogUtil.info("地址信息 : {}" , object);
            String string = object.getJSONObject("result").getJSONObject("ad_info").getString("name");
            if (string.contains("上海市") || string.contains("重庆市") || string.contains("天津市") || string.contains("北京市") ||
                    string.contains("广州市")) {
                address = object.getJSONObject("result").getJSONObject("ad_info").getString("district");
            } else {
                address = object.getJSONObject("result").getJSONObject("address_reference").getJSONObject("town").getString("title");
            }
            sysLocation = getOneForUpdate(new QueryWrapper<SysLocation>().eq(SysLocation.NAME, address));
            // 如果获取地址对象失败,即 地址名称不是区级 则重定为 区级获取
            if(!CommUtil.checkNull(sysLocation)){
                sysLocation = getOneForUpdate(new QueryWrapper<SysLocation>().eq(SysLocation.NAME,
                        string.split(",")[3]));
            }
        } catch (Exception e) {
            throw new ServiceException("获取地区信息错误");
        }
        return sysLocation;
    }


    @Override
    public List<SysLocationTreeVO> tree() {
        // 得到基础列表
        List<SysLocation> baseList  = sysLocationMapper.selectList(null);
        // 初始化树
        List<SysLocationTreeVO> tree = new ArrayList<SysLocationTreeVO>();
        // 初始化 val , item 映射
        HashMap<String, SysLocationTreeVO> map = new HashMap<>();
        //初始化树 以及 顶级地址
        baseList.forEach(e->{
            SysLocationTreeVO vo = new SysLocationTreeVO().setSubList(new ArrayList<SysLocationTreeVO>());
            BeanUtils.copyProperties(e,vo);
            if (e.getParentVal() == null) {
                tree.add(vo);
            }
            //为所有地址对象简历映射
            map.put(e.getVal(),vo);
        });

        //开始执行分类
        baseList.forEach(e -> {
            // 不是顶级添加分类树
            if (e.getParentVal() != null) {
                // 得到父级对象
                SysLocationTreeVO pVO = map.get(e.getParentVal());
                // 得到子类对象
                SysLocationTreeVO sVO = map.get(e.getVal());
                // 如果父对象地址名称 与 子对象地址名称一致 则表示为直辖市 将子级 直接 变为父级
                if(pVO.getName().equals(sVO.getName())){
                    BeanUtils.copyProperties(sVO,pVO);
                }else{
                    // 将子级对象添加到父级列表中
                    pVO.getSubList().add(sVO);
                }
            }
        });
        return tree;
    }

    @Override
    public List<Integer> getSubIdListByParentId(List<Integer> pIds) {
        List<SysLocation> list;
        // 得到地区列表
        if (redisUtil.hasKey("location")) {
             list = (List<SysLocation>) redisUtil.get("location");
        } else {
            list = list();
            redisUtil.set("location", list);

        }
        // 准备映射 key: pVal  , value : 子级地区列表
        HashMap<String, List<SysLocation>> map = new HashMap<>();
        // 父级地址对象
        List<SysLocation> pList = sysLocationMapper.selectList(
                new QueryWrapper<SysLocation>().in(SysLocation.ID, pIds));
        if (pList.isEmpty()){
            throw new ServiceException("地址信息错误请重选地址");
        }
        // 最子级id 列表
        List<Integer> result = new ArrayList<>();
        // 建立映射
        for (SysLocation location : list) {
            String parentVal = location.getParentVal();
            if (parentVal != null) {
                /* 如果 map 中 有 这个 key 就 得到 value 并往其中追加元素
                *  没有就建立并插入
                *  */
                if (map.containsKey(parentVal)) {
                    map.get(parentVal).add(location);
                }else{
                    List<SysLocation> subList = new ArrayList<>();
                    subList.add(location);
                    map.put(parentVal, subList);
                }
            }
        }

        for (SysLocation item : pList) {
            // 如果 subList == null表示当前 对象已经是最子级 id 则直接跳过本次循环并且 添加到结果列表中
            List<SysLocation> subList = map.get(item.getVal());
            if(subList == null) {
                result.add(item.getId());
                continue;
            }
            String val = subList.get(0).getVal();
            // 如果此时 map.get(val) == null 表示 当前列表  已经是最子级列表 直接添加到 result 中
            if(map.get(val) == null) {
                subList.forEach(e -> result.add(e.getId()));
                continue;
            }

            // 如果 size != 0 则表示当前 列表 的层级 为 2  需要双层遍历插入 result
            for (SysLocation sItem : subList) {
                List<SysLocation> sub = map.get(sItem.getVal());
                /*如果 等于 0 表示 当前地址为最子级地址*/
                if(sub == null){
                    result.add(sItem.getId());
                    continue;
                }
                // 如果不等于 0 则 表示 sub 为 最子级 列表
                sub.forEach(e -> result.add(e.getId()));
            }

        }
        return result;
    }

    @Override
    public String getParentNamesByIds(List<Integer> ids) {
        List<SysLocation> list;
        // 得到地区列表
        if (redisUtil.hasKey("location")) {
            list = (List<SysLocation>) redisUtil.get("location");
        } else {
            list = list();
            redisUtil.set("location", list);
        }

        // val : 地区对象 映射
        HashMap<String, SysLocation> valMap = new HashMap<>();
        list.forEach(e -> valMap.put(e.getVal(),e));

        // id : 地区对象 映射
        HashMap<Integer, SysLocation> idMap = new HashMap<>();
        list.forEach(e -> idMap.put(e.getId(),e));

        List<SysLocation> sysLocations = new ArrayList<>();
        for (Integer id : ids) {
            sysLocations.add(idMap.get(id));
        }
        if (sysLocations.isEmpty()) {
            return null;
        }
        HashSet<String> pNames = new HashSet<>();
        sysLocations.forEach(e -> {
            SysLocation now = e;
            // 循环得到最上父级
            while(now.getParentVal() != null){
                now = valMap.get(now.getParentVal());
            }
            pNames.add(now.getName());
        });
        StringBuilder result = new StringBuilder();
        pNames.forEach(e -> result.append(e).append("/"));
        return result.deleteCharAt(result.length()-1).toString();
    }
}
